#include "WorldMap.h"
#include "NameGenerator.h"

WorldMap::WorldMap(Character* aHero, int aSeed) : Map(aHero, aSeed)
{
	fprintf(stderr, "> World map constructor...");

	_mapType = MAP_WORLD;
  _generator = PERLIN;

	Generate(120,100);

	fprintf(stderr, " - OK\n");
}

WorldMap::~WorldMap()
{
}

void WorldMap::GenerateMapData(){
	static int generationCount = 1;
	fprintf(stderr, "\n> Land generator (%d)\n",generationCount++);
	switch(_generator){
	case PERLIN: generatePerlin(); break;
	case ALEXANDER:	generateAlexander(); break;
	}
	generateBiomes();

	// Passable tile set and cities
	int citiesCounter = 0;
	for(int x=0; x<_tilesX; x++)
	for(int y=0; y<_tilesY; y++)
	{
		int t = getUpper(x,y);
		if(t == EMPTY || t == BRIDGE || t == CITY || t == ROAD || t == PORT) SetPassable(x,y,true);

		if(t == CITY)
		{
			Node n = {x,y};
			cities.push_back(n);
			citiesNames.push_back(NameGenerator::GenerateCityName());
			citiesCounter++;
		}
	}
}

Node WorldMap::GetHeroSpawn(int aFacing)
{
	if(aFacing == -1)
	{
		int randomCity = rand()%cities.size();
		lastSpawn = cities[randomCity];
		for(int d=0; d<4; d++)
			if(getUpper(lastSpawn.x+dir[d][0],lastSpawn.y+dir[d][1]) == ROAD || 
				 getUpper(lastSpawn.x+dir[d][0],lastSpawn.y+dir[d][1]) == BRIDGE)
			{
				lastSpawn.x += dir[d][0];
				lastSpawn.y += dir[d][1];
				break;
			}
	}
	else
	{
		if(aFacing == LEFT && IsPassable(lastSpawn.x-1,lastSpawn.y)) lastSpawn.x--;
		else if(aFacing == RIGHT && IsPassable(lastSpawn.x+1,lastSpawn.y)) lastSpawn.x++;
		else if(aFacing == UP && IsPassable(lastSpawn.x,lastSpawn.y-1)) lastSpawn.y--;
		else if(aFacing == DOWN && IsPassable(lastSpawn.x,lastSpawn.y+1)) lastSpawn.y++;
		else
		{
			for(int d=0; d<4; d++)
				if(getUpper(lastSpawn.x+dir[d][0],lastSpawn.y+dir[d][1]) == ROAD || 
					 getUpper(lastSpawn.x+dir[d][0],lastSpawn.y+dir[d][1]) == BRIDGE)
				{
					lastSpawn.x += dir[d][0];
					lastSpawn.y += dir[d][1];
					break;
				}
		}
	}

	return lastSpawn;
}

void WorldMap::SaveHeroSpawn(Node aSpawn)
{
	lastSpawn = aSpawn;
}

void WorldMap::findOceans(int aX, int aY){
	if(getLower(aX,aY) == WATER){
		setLower(aX,aY,OCEAN);
		for(int d=0; d<4; d++)
			if(getLower(aX+dir[d][0],aY+dir[d][1]) != OCEAN) findOceans(aX+dir[d][0],aY+dir[d][1]);
	}
	else{
		setLower(aX,aY,COAST);
		return;
	}
}

void WorldMap::generateBiomes(){
	// find oceans and coasts
	fprintf(stderr, "  - Oceans and coasts\n");
	for(int i=0; i<_tilesX; i++){
		if(getLower(i,0) == WATER) findOceans(i,0);
		if(getLower(i,_tilesY-1) == WATER) findOceans(i,_tilesY-1);
	}
	for(int i=0; i<_tilesY; i++){
		if(getLower(0,i) == WATER) findOceans(0,i);
		if(getLower(_tilesX-1,i) == WATER) findOceans(_tilesX-1,i);
	}
		
	// mark the rest of the water as lakes
	fprintf(stderr, "  - Lakes\n");
	for(int i=0; i<_tilesX; i++)
		for(int j=0; j<_tilesY; j++){
			if(getLower(i,j) == WATER) setLower(i,j,LAKE);
		}

	// remove single tiles
	for(int i=0; i<_tilesX; i++)
		for(int j=0; j<_tilesY; j++){
			int t = getLower(i,j);
			if(t == COAST) continue;
			int d;
			for(d=0; d<4; d++) if(getLower(i+dir[d][0],j+dir[d][1]) == t) break;
			if(d==4){
				int n;
				do{
				int r = rand()%4;
				n = getLower(i+dir[r][0],j+dir[r][1]);
				} while(n == NONE);
				setLower(i,j,n);
			}
		}

	// generate terrain
	generateTerrain();
}